﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace FileSplit
{
    public partial class FileSplitForm : Form
    {
        private string[] m_arguments;
        private Workers.Splitter m_splitter = new Workers.Splitter();
        private Workers.Joiner m_joiner = new Workers.Joiner();

        public FileSplitForm(string[] arguments)
        {
            InitializeComponent();
            m_arguments = arguments;
        }

        private void FileSplitForm_Load(object sender, EventArgs e)
        {
            m_versionTextBox.Text = "0.1.0";
            
            m_splitFolderDialog.ShowNewFolderButton = true;

            m_sizeComboBox.Items.Add("KB");
            m_sizeComboBox.Items.Add("MB");
            m_sizeComboBox.SelectedIndex = 0;

            m_splitButton.Enabled = IsReadyToSplit();
            m_joinButton.Enabled = IsReadyToJoin();

            TryJoinUsingArgument();
        }

        private void SplitFileDialogButton_Click(object sender, EventArgs e)
        {
            if (IsSourceFileValid(m_fileToSplitTextBox.Text))
                m_splitFileDialog.FileName = m_fileToSplitTextBox.Text;

            if (m_splitFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                m_fileToSplitTextBox.Text = m_splitFileDialog.FileName;                
            }
        }

        private void SplitFolderDialogButton_Click(object sender, EventArgs e)
        {
            if (m_splitFolderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                m_splitDestinationTextBox.Text = m_splitFolderDialog.SelectedPath;
        }

        private void JoinFileDialogButton_Click(object sender, EventArgs e)
        {
            if (IsSourceFileValid(m_fileToJoinTextBox.Text))
                m_joinFileDialog.FileName = m_fileToJoinTextBox.Text;

            if (m_joinFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                m_fileToJoinTextBox.Text = m_joinFileDialog.FileName;                
            }
        }

        private void JoinFolderDialogButton_Click(object sender, EventArgs e)
        {
            if (m_joinFolderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                m_joinDestinationTextBox.Text = m_joinFolderDialog.SelectedPath;
        }

        private void FileToSplitTextBox_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_splitDestinationTextBox.Text.Trim()))
                m_splitDestinationTextBox.Text = Path.GetDirectoryName(m_fileToSplitTextBox.Text);
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void TextBoxes_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }
        
        private void TextBoxes_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] data = e.Data.GetData(DataFormats.FileDrop) as string[];
                (sender as TextBox).Text = data[0];
            }
            else if (e.Data.GetDataPresent(DataFormats.Text))
            {
                (sender as TextBox).Text = e.Data.GetData(DataFormats.Text).ToString();
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void SplitDestinationTextBox_TextChanged(object sender, EventArgs e)
        {
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void FileToJoinTextBox_TextChanged(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(m_joinDestinationTextBox.Text.Trim()))
                m_joinDestinationTextBox.Text = Path.GetDirectoryName(m_fileToJoinTextBox.Text);
            m_joinButton.Enabled = IsReadyToJoin();
        }

        private void JoinDestinationTextBox_TextChanged(object sender, EventArgs e)
        {
            m_joinButton.Enabled = IsReadyToJoin();
        }

        private void SizeTextBox_TextChanged(object sender, EventArgs e)
        {
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void FileCountTextBox_TextChanged(object sender, EventArgs e)
        {
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void SizeRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            m_sizeTextBox.Enabled = m_sizeComboBox.Enabled = m_sizeRadioButton.Checked;
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void FileCountRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            m_fileCountTextBox.Enabled = m_fileCountRadioButton.Checked;
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void SplitButton_Click(object sender, EventArgs e)
        {
            m_splitProgressLabel.Text = "Splitting...";
            m_splitButton.Enabled = false;

            int splitSize = 0;
            if (m_sizeRadioButton.Checked)
            {
                splitSize = int.Parse(m_sizeTextBox.Text) * 1024;
                if (m_sizeComboBox.SelectedItem.ToString() == "MB") splitSize *= 1024;
            }
            else
            {
                int fileCount = int.Parse(m_fileCountTextBox.Text);
                long fileSize = new FileInfo(m_fileToSplitTextBox.Text).Length;
                splitSize = (int)(fileSize / fileCount);

                if (fileSize % fileCount > 0)
                {
                    while (fileCount - 1 != fileSize / splitSize)
                    {
                        splitSize += 1;
                    }
                }
            }

            string destinationPath = m_splitDestinationTextBox.Text;
            if (destinationPath.Substring(destinationPath.Length - 1) == Path.DirectorySeparatorChar.ToString())
            {
                destinationPath = destinationPath.Substring(0, destinationPath.Length - 1);
            }

            try
            {
                File.Copy(Application.ExecutablePath, destinationPath +
                    Path.DirectorySeparatorChar + Path.GetFileName(Application.ExecutablePath), true);
            }
            catch (IOException)
            {
                // On purpose, ignore.  In the case where the destination is where the app exists, 
                // copying the app to itself causes this exception.
            }

            using (FileStream writeFs = new FileStream(destinationPath +
                Path.DirectorySeparatorChar + "Join to " + Path.GetFileName(m_fileToSplitTextBox.Text) + ".bat",
                FileMode.Create))
            {
                using (StreamWriter sw = new StreamWriter(writeFs))
                {
                    sw.WriteLine(Path.GetFileName(Application.ExecutablePath) + " \"" +
                        Path.GetFileName(m_fileToSplitTextBox.Text) + ".1" + "\"");
                    sw.Write("exit");
                }
            }

            m_splitter.BackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(Splitter_ProgressChanged);
            m_splitter.BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Splitter_RunWorkerCompleted);
            m_splitter.Run(m_fileToSplitTextBox.Text, m_splitDestinationTextBox.Text, splitSize);
        }

        private void JoinButton_Click(object sender, EventArgs e)
        {
            DoJoin();
        }

        private void CancelSplitButton_Click(object sender, EventArgs e)
        {
            m_splitter.BackgroundWorker.CancelAsync();
        }

        private void CancelJoinButton_Click(object sender, EventArgs e)
        {
            m_joiner.BackgroundWorker.CancelAsync();
        }

        private void Splitter_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            m_splitProgressBar.Value = e.ProgressPercentage;            
        }

        private void Splitter_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                m_splitProgressLabel.Text = "Cancelled";
                m_splitProgressBar.Value = 100;
            }
            else
            {
                m_splitProgressLabel.Text = "Done";
            }
            m_splitButton.Enabled = IsReadyToSplit();
        }

        private void TryJoinUsingArgument()
        {
            if (!IsArgumentValid()) return;

            m_fileToJoinTextBox.Text = Path.GetDirectoryName(Application.ExecutablePath) + 
                Path.DirectorySeparatorChar + m_arguments[0];
            m_joinDestinationTextBox.Text = Path.GetDirectoryName(Application.ExecutablePath);
            if(!IsReadyToJoin()) return;

            m_tabControl.SelectedTab = m_joinTab;
            DoJoin();
        }

        private void DoJoin()
        {
            m_joinProgressLabel.Text = "Joining...";
            m_joiner.BackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(Joiner_ProgressChanged);
            m_joiner.BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Joiner_RunWorkerCompleted);
            m_joiner.Run(m_fileToJoinTextBox.Text, m_joinDestinationTextBox.Text);
        }

        private void Joiner_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            m_joinProgressBar.Value = e.ProgressPercentage;            
        }

        private void Joiner_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                m_joinProgressLabel.Text = "Cancelled";                
            }
            else
            {
                m_joinProgressLabel.Text = "Done";
            }
            
            m_joinProgressBar.Value = 100;
            m_joinProgressBar.Value = 99;
            m_joinProgressBar.Value = 100;

            m_joinButton.Enabled = IsReadyToJoin();
            if (IsArgumentValid())
            {
                System.Threading.Thread.Sleep(2000);
                Application.Exit();
            }
        }

        private bool IsReadyToSplit()
        {
            return IsSourceFileValid(m_fileToSplitTextBox.Text) && 
                IsDestinationDirectoryValid(m_splitDestinationTextBox.Text) && IsSplitTypeValid();
        }

        private bool IsReadyToJoin()
        {
            return IsSourceFileValid(m_fileToJoinTextBox.Text) && IsFirstSplitFile(m_fileToJoinTextBox.Text) && 
                IsDestinationDirectoryValid(m_joinDestinationTextBox.Text);
        }

        private bool IsSourceFileValid(string sourceFile)
        {
            return File.Exists(sourceFile);
        }

        private bool IsDestinationDirectoryValid(string path)
        {
            return Directory.Exists(path);
        }

        private bool IsSplitTypeValid()
        {
            if (m_sizeRadioButton.Checked)
            {
                try
                {
                    long splitSize = long.Parse(m_sizeTextBox.Text);
                    splitSize *= 1024;
                    if (m_sizeComboBox.SelectedItem.ToString() == "MB") splitSize *= 1024;
                    long fileSize = new FileInfo(m_fileToSplitTextBox.Text).Length;
                    return (fileSize >= splitSize);
                }
                catch
                {                    
                }
            }
            else
            {
                try
                {
                    int.Parse(m_fileCountTextBox.Text);
                    return true;
                }
                catch
                {
                }
            }

            return false;
        }

        private bool IsFirstSplitFile(string fileName)
        {
            return (new FileInfo(fileName).Extension == ".1");
        }

        private bool IsArgumentValid()
        {
            if (m_arguments == null || m_arguments.Length != 1) return false;
            if (string.IsNullOrEmpty(m_arguments[0])) return false;
            return true;
        }
    }
}
